Maintain a list for the stacking order of windows. Implement lower and
authorRichard Hult <richard@imendio.com>
Tue, 23 Oct 2007 13:06:31 +0000 (13:06 +0000)
committerRichard Hult <rhult@src.gnome.org>
Tue, 23 Oct 2007 13:06:31 +0000 (13:06 +0000)
2007-10-23  Richard Hult  <richard@imendio.com>

* gdk/quartz/gdkwindow-quartz.c:
(gdk_window_raise, gdk_window_lower, gdk_window_new,
_gdk_windowing_window_destroy): Maintain a list for the stacking
order of windows. Implement lower and raise for child windows. The
list for toplevels is created on demand, and cleared when a window
gets or resigns main status and when new windows are created.
(find_child_window_helper): Use the sorted list to go through
windows from top to bottom. Take any titlebar in consideration for
toplevels, to stop events from sometimes punching through (bugs
#473813 and #489370).

svn path=/trunk/; revision=18940

ChangeLog
gdk/quartz/gdkwindow-quartz.c
gdk/quartz/gdkwindow-quartz.h

index 994f62a711321864588f3981903852937bd95848..4aee52dd918743a0a8dad171d1b2e5d8f8dc6ad3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2007-10-23  Richard Hult  <richard@imendio.com>
+
+       * gdk/quartz/gdkwindow-quartz.c:
+       (gdk_window_raise, gdk_window_lower, gdk_window_new,
+       _gdk_windowing_window_destroy): Maintain a list for the stacking
+       order of windows. Implement lower and raise for child windows. The
+       list for toplevels is created on demand, and cleared when a window
+       gets or resigns main status and when new windows are created.
+       (find_child_window_helper): Use the sorted list to go through
+       windows from top to bottom. Take any titlebar in consideration for
+       toplevels, to stop events from sometimes punching through (bugs
+       #473813 and #489370).
+
 2007-10-22  Johan Dahlin  <jdahlin@async.com.br>
 
        * gtk/gtkbuilder.c: Use gtk_ascii_tolower/toupper instead of the C 
index cfb831b27f16b719f7f2cd0efff725d2fdde82f9..e63491827ee8d5c85c752a1a6fd11a9de32788e2 100644 (file)
@@ -32,6 +32,9 @@ static guint   update_idle;
 
 static GSList *main_window_stack;
 
+static void update_toplevel_order (void);
+static void clear_toplevel_order (void);
+
 #define WINDOW_IS_TOPLEVEL(window)                \
   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD && \
    GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
@@ -467,23 +470,59 @@ find_child_window_helper (GdkWindow *window,
                          gint       x_offset,
                          gint       y_offset)
 {
+  GdkWindowImplQuartz *impl;
   GList *l;
 
-  for (l = GDK_WINDOW_OBJECT (window)->children; l; l = l->next)
+  impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
+
+  if (window == _gdk_root)
+    update_toplevel_order ();
+
+  for (l = impl->sorted_children; l; l = l->next)
     {
-      GdkWindowObject *private = l->data;
-      GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
+      GdkWindowObject *child_private = l->data;
+      GdkWindowImplQuartz *child_impl = GDK_WINDOW_IMPL_QUARTZ (child_private->impl);
       int temp_x, temp_y;
 
-      if (!GDK_WINDOW_IS_MAPPED (private))
+      if (!GDK_WINDOW_IS_MAPPED (child_private))
        continue;
 
-      temp_x = x_offset + private->x;
-      temp_y = y_offset + private->y;
-      
-      /* FIXME: Are there off by one errors here? */
+      temp_x = x_offset + child_private->x;
+      temp_y = y_offset + child_private->y;
+
+      /* Special-case the root window. We have to include the title
+       * bar in the checks, otherwise the window below the title bar
+       * will be found i.e. events punch through. (If we can find a
+       * better way to deal with the events in gdkevents-quartz, this
+       * might not be needed.)
+       */
+      if (window == _gdk_root)
+        {
+          NSRect frame = NSMakeRect (0, 0, 100, 100);
+          NSRect content;
+          int mask;
+          int titlebar_height;
+
+          mask = [child_impl->toplevel styleMask];
+
+          /* Get the title bar height. */
+          content = [NSWindow contentRectForFrameRect:frame
+                                            styleMask:mask];
+          titlebar_height = frame.size.height - content.size.height;
+
+          if (titlebar_height > 0 &&
+              x >= temp_x && y >= temp_y - titlebar_height &&
+              x < temp_x + child_impl->width && y < temp_y)
+            {
+              /* The root means "unknown" i.e. a window not managed by
+               * GDK.
+               */
+              return (GdkWindow *)_gdk_root;
+            }
+        }
+
       if (x >= temp_x && y >= temp_y &&
-         x < temp_x + impl->width && y < temp_y + impl->height) 
+         x < temp_x + child_impl->width && y < temp_y + child_impl->height)
        {
          /* Look for child windows. */
          return find_child_window_helper (l->data,
@@ -520,6 +559,8 @@ _gdk_quartz_window_did_become_main (GdkWindow *window)
 
   if (GDK_WINDOW_OBJECT (window)->window_type != GDK_WINDOW_TEMP)
     main_window_stack = g_slist_prepend (main_window_stack, window);
+
+  clear_toplevel_order ();
 }
 
 void
@@ -549,6 +590,8 @@ _gdk_quartz_window_did_resign_main (GdkWindow *window)
 
       [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
     }
+
+  clear_toplevel_order ();
 }
 
 GdkWindow *
@@ -561,6 +604,7 @@ gdk_window_new (GdkWindow     *parent,
   GdkWindowImplQuartz *impl;
   GdkDrawableImplQuartz *draw_impl;
   GdkVisual *visual;
+  GdkWindowImplQuartz *parent_impl;
 
   if (parent && GDK_WINDOW_DESTROYED (parent))
     return NULL;
@@ -577,6 +621,7 @@ gdk_window_new (GdkWindow     *parent,
   draw_impl->wrapper = GDK_DRAWABLE (window);
 
   private->parent = (GdkWindowObject *)parent;
+  parent_impl = GDK_WINDOW_IMPL_QUARTZ (private->parent->impl);
 
   private->accept_focus = TRUE;
   private->focus_on_map = TRUE;
@@ -675,8 +720,13 @@ gdk_window_new (GdkWindow     *parent,
       g_object_ref (draw_impl->colormap);
     }
 
-  if (private->parent)
-    private->parent->children = g_list_prepend (private->parent->children, window);
+  private->parent->children = g_list_prepend (private->parent->children, window);
+
+  /* Maintain the z-ordered list of children. */
+  if (parent != _gdk_root)
+    parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
+  else
+    clear_toplevel_order ();
 
   gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
                                  (attributes->cursor) :
@@ -796,9 +846,27 @@ _gdk_windowing_window_destroy (GdkWindow *window,
                               gboolean   recursing,
                               gboolean   foreign_destroy)
 {
+  GdkWindowObject *private;
+  GdkWindowImplQuartz *impl;
+  GdkWindowObject *parent;
+
+  private = GDK_WINDOW_OBJECT (window);
+  impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
+
   update_windows = g_slist_remove (update_windows, window);
   main_window_stack = g_slist_remove (main_window_stack, window);
 
+  g_list_free (impl->sorted_children);
+  impl->sorted_children = NULL;
+
+  parent = private->parent;
+  if (parent)
+    {
+      GdkWindowImplQuartz *parent_impl = GDK_WINDOW_IMPL_QUARTZ (parent->impl);
+
+      parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
+    }
+
   /* If the destroyed window was targeted for a pointer or keyboard
    * grab, release the grab.
    */
@@ -1284,6 +1352,53 @@ _gdk_windowing_window_clear_area_e (GdkWindow *window,
   /* FIXME: Implement */
 }
 
+/* Get the toplevel ordering from NSApp and update our own list. We do
+ * this on demand since the NSApp's list is not up to date directly
+ * after we get windowDidBecomeMain.
+ */
+static void
+update_toplevel_order (void)
+{
+  GdkWindowObject *root;
+  GdkWindowImplQuartz *root_impl;
+  NSEnumerator *enumerator;
+  id nswindow;
+  GList *toplevels = NULL;
+
+  root = GDK_WINDOW_OBJECT (_gdk_root);
+  root_impl = GDK_WINDOW_IMPL_QUARTZ (root->impl);
+
+  if (root_impl->sorted_children)
+    return;
+
+  enumerator = [[NSApp orderedWindows] objectEnumerator];
+  while ((nswindow = [enumerator nextObject]))
+    {
+      GdkWindow *window;
+
+      if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
+        continue;
+
+      window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
+      toplevels = g_list_prepend (toplevels, window);
+    }
+
+  root_impl->sorted_children = g_list_reverse (toplevels);
+}
+
+static void
+clear_toplevel_order (void)
+{
+  GdkWindowObject *root;
+  GdkWindowImplQuartz *root_impl;
+
+  root = GDK_WINDOW_OBJECT (_gdk_root);
+  root_impl = GDK_WINDOW_IMPL_QUARTZ (root->impl);
+
+  g_list_free (root_impl->sorted_children);
+  root_impl->sorted_children = NULL;
+}
+
 void
 gdk_window_raise (GdkWindow *window)
 {
@@ -1292,13 +1407,28 @@ gdk_window_raise (GdkWindow *window)
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  /* FIXME: Only supported for toplevels currently. */
   if (WINDOW_IS_TOPLEVEL (window))
     {
       GdkWindowImplQuartz *impl;
 
       impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
       [impl->toplevel orderFront:impl->toplevel];
+
+      clear_toplevel_order ();
+    }
+  else
+    {
+      GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent;
+
+      if (parent)
+        {
+          GdkWindowImplQuartz *impl;
+
+          impl = (GdkWindowImplQuartz *)parent->impl;
+
+          impl->sorted_children = g_list_remove (impl->sorted_children, window);
+          impl->sorted_children = g_list_prepend (impl->sorted_children, window);
+        }
     }
 }
 
@@ -1310,13 +1440,28 @@ gdk_window_lower (GdkWindow *window)
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  /* FIXME: Only supported for toplevels currently. */
   if (WINDOW_IS_TOPLEVEL (window))
     {
       GdkWindowImplQuartz *impl;
 
       impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
       [impl->toplevel orderBack:impl->toplevel];
+
+      clear_toplevel_order ();
+    }
+  else
+    {
+      GdkWindowObject *parent = GDK_WINDOW_OBJECT (window)->parent;
+
+      if (parent)
+        {
+          GdkWindowImplQuartz *impl;
+
+          impl = (GdkWindowImplQuartz *)parent->impl;
+
+          impl->sorted_children = g_list_remove (impl->sorted_children, window);
+          impl->sorted_children = g_list_append (impl->sorted_children, window);
+        }
     }
 }
 
@@ -2572,7 +2717,6 @@ gdk_window_unfullscreen (GdkWindow *window)
 
   if (geometry)
     {
-
       ShowMenuBar ();
 
       move_resize_window_internal (window,
index ce5e0ba520ac445eaac71526783d2f4a2ef2c9c7..090c0cca0ffd5f3f626e841ca394a5a678ace653 100644 (file)
@@ -66,6 +66,9 @@ struct _GdkWindowImplQuartz
   gint in_paint_rect_count;
 
   GdkWindow *transient_for;
+
+  /* Sorted by z-order */
+  GList *sorted_children;
 };
  
 struct _GdkWindowImplQuartzClass